/////////////////////////////////////////////////////////////////////////////////////
// Include Files
#include "Objects\Water.h"

// HACK: raising events in CGame
#include "Main\Game.h"

// managers
#include "Managers\MeshManager.h"

// rendering
#include "Rendering\RenderState.h"

#include <math.h>

/////////////////////////////////////////////////////////////////////////////////////
// CWater Implementation

CWater::CWater() : ABCObject()
{
	// create the render state
	m_pRenderState = new CRenderState();
	m_pRenderState->AddRef();

	// mesh
	m_pRenderState->SetMesh(L"Water.mesh");

	// shader
	m_pRenderState->SetShader(L"Water.cgfx");

	// matrices
	matrix_t matTransform = Matrix();
	m_pRenderState->SetTransform(matTransform);

	// TODO: these should be in the shader file like how Flux does it: g_matModelViewProj : PARAM_MAT_MODELVIEW; passed through the shader constants?
	m_pRenderState->SetMatrixParam(L"g_matModelView", PARAM_MAT_MODELVIEW);
	m_pRenderState->SetMatrixParam(L"g_matModelViewProj", PARAM_MAT_MODELVIEWPROJ);

	// textures
#pragma warning(disable:981)
	m_pRenderState->AddTexParam(L"WaterBase.tex2d", L"Water1Sampler");
	m_pRenderState->AddTexParam(L"WaterTop.tex2d", L"Water2Sampler");
#pragma warning(default:981)

	// HACK: raising event in CGame
	CSingleton<CGame>()->RenderStateAdd.Raise(new CRenderStateEventArg(m_pRenderState));

	// HACK: creating a copy of the mesh
	for( int_t x = 0; x < 101; ++x )
	{
		for( int_t z = 0; z < 101; ++z )
		{
			float_t fX = (50.0f - x) * 10.0f;
			float_t fZ = (50.0f - z) * 10.0f;

			arrVertices[x][z].pos[0] = fX;
			arrVertices[x][z].pos[1] = 0.0f;
			arrVertices[x][z].pos[2] = fZ;

			arrVertices[x][z].tex0[0] = fX / 200.0f;
			arrVertices[x][z].tex0[1] = fZ / 200.0f;

			arrVertices[x][z].tex1[0] = fX / 50.0f;
			arrVertices[x][z].tex1[1] = fZ / 50.0f;
		}
	}
}

CWater::~CWater()
{
	// HACK: raising event in CGame
	CSingleton<CGame>()->RenderStateRemove.Raise(new CRenderStateEventArg(m_pRenderState));
	m_pRenderState->Release();
}

void CWater::Update( float_t _fTime )
{
	// keep track of the total elapsed time
	static float m_fElapsed = 0.0f;
	m_fElapsed += _fTime;

	for( int_t x = 0; x < 101; ++x )
	{
		for( int_t z = 0; z < 101; ++z )
		{
			// adjust the vertex height
			float_t fHeight = 0.0f;
			fHeight += sin(z * 0.5f + m_fElapsed) * 5.0f;
			fHeight += sin(x * 0.25f + m_fElapsed * 0.75f) * 2.0f;
			arrVertices[x][z].pos[1] = fHeight;

			// adjust the texture coordinates
			arrVertices[x][z].tex0[1] -= 0.05f * _fTime;
			arrVertices[x][z].tex1[0] -= 0.10f * _fTime;
		}
	}

	// copy the new vertex data into a new buffer
	uint_t uSize = 101 * 101 * sizeof(Vert);
	byte_t *pData = new byte_t[uSize];
	memcpy(pData, arrVertices, uSize);

	// send the update event
	CMeshEventArg *pArg = new CMeshEventArg(L"Water.mesh");
	pArg->SetVertexData(uSize, pData);
	m_pMeshManager->MeshUpdate.Raise(pArg);
}
